package org.ala.tcp_feign_server.context.heart;

import java.util.Iterator;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.ala.tcp_feign_common.config.AttrbuteKeyNamespace;
import org.ala.tcp_feign_common.enums.TcpFeignCloseTypeEnums;
import org.ala.tcp_feign_common.logs.LoggerFactory;
import org.ala.tcp_feign_server.context.TcpFeignServerContext;
import org.slf4j.Logger;

import io.netty.channel.Channel;
import io.netty.util.AttributeKey;

/**
 * 心跳检测队列
 * 
 * @author 骆毅(ala)
 * @date 2024年4月19日
 */
public class WaitForHeartQueue {
	
	
	static Logger log = LoggerFactory.getLogger("tcp-feign", "server");

	
	/**
	 * 心跳间隔
	 * <p>	单位：毫秒
	 * <p>	默认：10s
	 */
	protected long interval = 10000l;
	/**
	 * 允许的心跳失败次数
	 * <p>	默认：6次
	 * <p>	也就是说1分钟内收不到心跳的连接，将被判定为失效
	 */
	protected int allowFailTimes = 6;
	/**
	 * 允许的间隔
	 */
	protected long allowInterval;
	/**
	 * 
	 */
	protected ScheduledExecutorService scheduled;
	
	
	/**
	 * 初始化
	 */
	public void init(long interval, int allowFailTimes) {
		this.interval = interval;
		this.allowFailTimes = allowFailTimes;
		this.allowInterval = interval * allowFailTimes;
		
		//	开启定时任务
		long intvl = interval * allowFailTimes;
		scheduled = Executors.newScheduledThreadPool(1);
		scheduled.scheduleAtFixedRate(() -> scanActiveChannel(), intvl/2, intvl/2, TimeUnit.MILLISECONDS);
	}
	/**
	 * 扫描当前全部活跃channel
	 */
	protected void scanActiveChannel() {
//		log.info("[WaitForLoginQueue check] 开始心跳检测");
		
		Iterator<Channel> channels = TcpFeignServerContext.instance().getActiveChannelMapper().values().iterator();
		Long now = System.currentTimeMillis();
		while (channels.hasNext()) {
			Channel channel = channels.next();
			
			//	检测上次心跳时间
			Long timestamp = (Long)channel.attr(AttributeKey.valueOf(AttrbuteKeyNamespace.HEART)).get();
			//	如果为空，则检测3次握手时间戳
			if (timestamp == null) {
				timestamp = (Long)channel.attr(AttributeKey.valueOf(AttrbuteKeyNamespace.CONNECT_TIMESTAMP)).get();
			}
			if (timestamp == null) {
				log.info("[WaitForLoginQueue check] 链接没有上次心跳时间戳，也没有3次握手时间戳，咋混进来的。。。 即将关闭. remoteAddress:" + channel.remoteAddress());
				
				TcpFeignServerContext.instance().closeClient(channel, TcpFeignCloseTypeEnums.HEART_ERROR);
				continue;
			}
			
			//	如果已经超过允许的最大间隔，断掉链接
			if (now - timestamp > allowInterval) {
				log.info("[WaitForLoginQueue check] 检测到心跳超时的连接，即将关闭. remoteAddress:" + channel.remoteAddress());
				
				TcpFeignServerContext.instance().closeClient(channel, TcpFeignCloseTypeEnums.HEART_ERROR);
				continue;
			}
		}
	}
	
	
}
